#include "disp_driver.h"
#include <stdio.h>

extern configuration config;

lcd_init_cmd_t st7735_init_cmds[] = {
    {ST7789_SWRESET, {0}, 0x80, 150},
    {ST7789_SLPOUT, {0}, 0x80, 250},
    {0xB1, {0x01, 0x2C, 0x2D}, 3},
    {0xB2, {0x01, 0x2C, 0x2D}, 3},
    {0xB3, {0x01, 0x2C, 0x2D, 0x01, 0x2C, 0x2D}, 6},
    {0xB4, {0x07}, 1},
    {0xC0, {0xA2, 0x02, 0x84}, 3},
    {0xC1, {0xC5}, 1},
    {0xC2, {0x0A, 0x00}, 2},
    {0xC3, {0x8A, 0x2A}, 2},
    {0xC4, {0x8A, 0xEE}, 2},
    {0xC5, {0x0E}, 1},
    {0x20, {0}, 0},
    {0x36, {0x50}, 1},
    {0x3A, {0x05}, 1},
    {0x2A, {0x00, 0x02, 0x00, 0x7F + 0x02}, 4},
    {0x2B, {0x00, 0x01, 0x00, 0x9F + 0x01}, 4},
    {0xE0,
     {
         0x02,
         0x1c,
         0x07,
         0x12,
         0x37,
         0x32,
         0x29,
         0x2d,
         0x29,
         0x25,
         0x2B,
         0x39,
         0x00,
         0x01,
         0x03,
         0x10,
     },
     16},
    {0xE1,
     {
         0x03,
         0x1d,
         0x07,
         0x06,
         0x2E,
         0x2C,
         0x29,
         0x2D,
         0x2E,
         0x2E,
         0x37,
         0x3F,
         0x00,
         0x00,
         0x02,
         0x10,
     },
     16},
    {0x13, {0}, 0x80, 10},
    {0x29, {0}, 0x80, 100},
    {0, {0}, 0xff}};

extern disp_driver_api api;
void st7735_api_init(void) {
    api.disp_init_cmd = st7735_init_cmds;
    api.disp_set_window = st7735_set_window;
    api.disp_set_orientation = st7735_set_orientation;
}
/* The ST7789 display controller can drive 320*240 displays, when using a
 * 240*240 display there's a gap of 80px, we need to edit the coordinates to
 * take into account that gap, this is not necessary in all orientations. */
void st7735_set_window(lv_disp_drv_t *drv, const lv_area_t *area) {
    uint8_t data[4] = {0};

    uint16_t offsetx1 = area->x1;
    uint16_t offsetx2 = area->x2;
    uint16_t offsety1 = area->y1;
    uint16_t offsety2 = area->y2;

    offsetx1 += config.offset_x;
    offsetx2 += config.offset_x;
    offsety1 += config.offset_y;
    offsety2 += config.offset_y;

    /*Column addresses*/
    disp_send_cmd(ST7789_CASET);
    data[0] = (offsetx1 >> 8) & 0xFF;
    data[1] = offsetx1 & 0xFF;
    data[2] = (offsetx2 >> 8) & 0xFF;
    data[3] = offsetx2 & 0xFF;
    disp_send_data(data, 4);

    /*Page addresses*/
    disp_send_cmd(ST7789_RASET);
    data[0] = (offsety1 >> 8) & 0xFF;
    data[1] = offsety1 & 0xFF;
    data[2] = (offsety2 >> 8) & 0xFF;
    data[3] = offsety2 & 0xFF;
    disp_send_data(data, 4);

    /*Memory write*/
    disp_send_cmd(ST7789_RAMWR);
}

void st7735_set_orientation(uint8_t orientation) {
    const char *orientation_str[] = {"PORTRAIT", "PORTRAIT_INVERTED",
                                     "LANDSCAPE", "LANDSCAPE_INVERTED"};

    printf("Display orientation: %s\n", orientation_str[orientation]);

    uint8_t data[4][2] = {
        {0x40U, 0xC0U}, /* Portrait orientation choice of LCD screen */
        {0x80U,
         0x00U}, /* Portrait rotated 180° orientation choice of LCD screen  */
        {0x20U, 0x60U}, /* Landscape orientation choice of LCD screen */
        {0xE0U,
         0xA0U} /* Landscape rotated 180° orientation choice of LCD screen */};

    disp_send_cmd(ST7789_MADCTL);
    disp_send_data((void *)&data[orientation], 2);
}